﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Company.Project.Application.Service.CacheService;
using Company.Project.Domain.Model.DTO.Manager;
using Company.Project.Infrastructure.Common.Enums;
using Company.Project.Web.Areas.Admin.Attrbute;
using Z.Nlayer.Utility;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace Company.Project.Web.Admin.Areas.Admin.Lib.Authorization
{
    public class AdminRoleHandler : AuthorizationHandler<AdminAuthorizationRequirement>
    {
        private readonly ILocalCommon _localCommon;
        private readonly IProject_SYS_BaseCacheService _cacheService;
        public AdminRoleHandler(ILocalCommon localCommon, IProject_SYS_BaseCacheService cacheService)
        {
            _localCommon = localCommon;
            _cacheService = cacheService;
        }
        public bool IsAuth { get; set; }
        public bool IskRole { get; set; }
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
            AdminAuthorizationRequirement requirement)
        {
            var filterContext = ((Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext) context.Resource);
            IsAuth = false;
            IskRole = !requirement.ChkRole;
            var user = await _localCommon.CurrentFullUserAsync();
            if (user.ID != Guid.Empty && user.State == Enum_ManagerUserState.Normal)
            {
                IsAuth = true;
            }
            if (requirement.ChkRole && IsAuth)
            {
                var controllerName = (filterContext.RouteData.Values["controller"]).ToString().ToLower();
                var actionName = string.IsNullOrEmpty(requirement.FatherModule) ?
                    filterContext.RouteData.Values["action"].ToString().ToLower() : requirement.FatherModule.ToLower();
                var areaName = (filterContext.RouteData.DataTokens["area"] ?? "").ToString().ToLower();
                //若控制器-方法不在权限列表中，直接略过
                if (user.DefActionList.Exists(
                    x => x.controllerName == controllerName && x.actionName == actionName && x.areaName == areaName))
                {
                    var allmodule =
                        user.UserActionList.Select(x => x.ModuleDtos).Aggregate<IEnumerable<RoleAction_ModuleDTO>>(
                            (a, b) => a.Concat(b)).ToList();
                    IskRole = allmodule.Exists(
                        x =>
                            x.controllerName == controllerName && x.actionName == actionName &&
                            x.areaName == areaName);
                }
                else
                {
                    //通过从属特性校验方法的权限
                    var fatherActions = new List<string>();
                    var cacheColumsName = _cacheService.GetCache<List<Tuple<string, List<string>>>>("subAuth");
                    var key = areaName + controllerName + actionName;
                    if (cacheColumsName != null)
                    {
                        if (cacheColumsName.Exists(x => x.Item1 == key))
                        {
                            fatherActions = cacheColumsName.FirstOrDefault(x => x.Item1 == key)?.Item2;
                        }
                        else
                        {
                            var subAuth = filterContext.ActionDescriptor.GetType().GetCustomAttributes(false).FirstOrDefault(x => x.GetType() == typeof(SubAuth));
                            if (subAuth != null)
                            {
                                fatherActions = ((SubAuth)subAuth).FatherName;
                                cacheColumsName.Add(new Tuple<string, List<string>>(key, fatherActions));
                                _cacheService.Add("subAuth", cacheColumsName);
                            }
                        }
                    }
                    else
                    {
                        //create
                        cacheColumsName = new List<Tuple<string, List<string>>>();
                        var subAuth = filterContext.ActionDescriptor.GetType().GetCustomAttributes(false).FirstOrDefault(x => x.GetType() == typeof(SubAuth));
                        if (subAuth != null)
                        {
                            fatherActions = ((SubAuth)subAuth).FatherName;
                            cacheColumsName.Add(new Tuple<string, List<string>>(key, fatherActions));
                            _cacheService.Add("subAuth", cacheColumsName);
                        }
                    }
                    if (fatherActions.Any())
                    {
                        fatherActions.ForEach(y =>
                        {
                            y = y.ToLower();
                            if (user.DefActionList.Exists(
                                x => x.controllerName == controllerName && x.actionName == y && x.areaName == areaName))
                            {
                                var allmodule =
                                    user.UserActionList.Select(x => x.ModuleDtos)
                                        .Aggregate<IEnumerable<RoleAction_ModuleDTO>>(
                                            (a, b) => a.Concat(b)).ToList();
                                if (allmodule.Exists(
                                    x =>
                                        x.controllerName == controllerName && x.actionName == y &&
                                        x.areaName == areaName))
                                {
                                    IskRole = true;
                                }
                            }
                        });
                    }
                    else
                    {
                        IskRole = true;
                    }
                }
            }
            if (IsAuth == false || IskRole == false)
            {
                if (filterContext.HttpContext.Request.IsAjaxRequest())
                {
                    filterContext.Result =
                        new JsonResult(new {Success = false, Message = !IsAuth ? "登录已过期,请重新登录!" : "权限不足,无法访问!"});
                    context.Succeed(requirement);
                }
                else
                {
                    context.Fail();
                }
                return;
            }
            context.Succeed(requirement);
        }
    }
}
